import Global
proc_name = ''
local_flag = 0
index = -1
s_index = 0
sav1 = ''
sav2 = ''
l_parameter = {}
l_value = []
env = ['.486\n.model flat, stdcall\noption casemap: none\n',
       'include     \masm32\include\windows.inc\n',
       'include     \masm32\include\kernel32.inc\n',
       'include     \masm32\include\msvcrt.inc\n',
       'includelib  \masm32\lib\kernel32.lib\n',
       'includelib  \masm32\lib\msvcrt.lib\n']
code = ['\n.code\n']
rodata = ['\n.data?\n',
          'sav1 dd ?\n',
          'sav2 dd ?\n']
data = ['\n.data\n']
tcode = []
registers = {'eax':'', 'ebx':'', 'ecx':'', 'edx':''}
backup = ['','','','','','']

def get4Tuple():
    global index
    index += 1
    return Global.tuples[index]

def haveReference(str1, str2):
    i = ''
    j = ''
    if str1 in l_parameter:
        if l_parameter[str1] == 'V':
            i='0'
        else :
            i='1'
    else :
        i='0'
        
    if str2 in l_parameter:
        if l_parameter[str2] == 'V':
            j='0'
        else :
            j='1'
    else :
        j='0'
    return i+j

def haveReference2(str):
    if str in l_parameter:
        if l_parameter[str] == 'V':
            return '0'
        else :
            return '1'
    else :
        return '0'

def getPointRegister(str):
    code.append('\tmov esi, '+str+'\n')
    reg = getRegister('['+str+']',' ')
    code.append('\tmov '+reg+', dword ptr [esi]\n')
    return reg
        
def freeRegister(reg):
    if registers[reg][0] == 'I' or registers[reg][0] == 'R':
        registers[reg] = ''
        printRegisters()

def printRegisters():
    Global.outputFile.write('\tregisters: eax: '+registers['eax']+' edx: '+registers['edx']+' ebx: '+registers['ebx']+' ecx: '+registers['ecx']+' sav1: '+sav1+' sav2: '+sav2+'\n')
        
def getRegister(str,str2):
    global sav1, sav2
    for reg in registers:
        if registers[reg] == str:
            return reg

    if sav1 == str:
        sav1 = ''
        reg = getRegister(str, ' ')
        code.append('\tmov '+reg+', sav1\n')
        printRegisters()
        return reg
    
    if sav2 == str:
        sav2 = ''
        reg = getRegister(str, ' ')
        code.append('\tmov '+reg+', sav2\n')
        printRegisters()
        return reg
        
    for reg in registers:   
        if registers[reg] == '':
            registers[reg] = str
            if str[0] != 'I' and str[0] != 'R' and str[0] != '[':
                code.append('\tmov '+reg+', '+str+'\n')            
            printRegisters()
            return reg
        
    for reg in registers: 
        if registers[reg][0] in ['0','1','2','3','4','5','6','7','8','9']:
            if reg != str2:
                registers[reg] = str
                if str[0] != 'I' and str[0] != 'R' and str[0] != '[':
                    code.append('\tmov '+reg+', '+str+'\n')            
                printRegisters()
                return reg

    for reg in registers:
        if registers[reg][0] != 'I' and registers[reg][0] != 'R':
            if reg != str2:
                registers[reg] = str
                if str[0] != 'I' and str[0] != 'R' and str[0] != '[':
                    code.append('\tmov '+reg+', '+str+'\n')
                printRegisters()
                return reg
    reg = ''
    if sav1 == '':
        sav1 = registers['eax']
        registers['eax'] = ''
        code.append('\tmov sav1, eax\n')
        reg = getRegister(str, ' ')
        printRegisters()
    else :
        sav2 = registers['eax']
        registers['eax'] = ''       
        code.append('\tmov sav2, eax\n')
        reg = getRegister(str, ' ')
        printRegisters()
    return reg

        
def print4Tuple(list, tuple):
    list.append('\n;('+tuple[0]+', '+tuple[1]+', '+tuple[2]+', '+tuple[3]+')\n')

def _pragmatics():
    global index, local_flag, l_parameter, s_index, code, tcode, sav1, sav2, l_value, proc_name
    tuple = get4Tuple()
    if tuple[1] == 'flag' and tuple[0] == '20':
        code.append('\t;registers: eax: '+registers['eax']+' edx: '+registers['edx']+' ebx: '+registers['ebx']+' ecx: '+registers['ecx']+' sav1: '+sav1+' sav2: '+sav2+'\n')
        return
    if tuple[1] == 'BEGINPROGRAM':
        code.append('start:\n\tcall main\n\tinvoke ExitProcess, 0\n')

    if tuple[1] == 'ENDPROGRAM':
        code.append('end start\n')

    elif tuple[1] == 'MEMORY':
        if local_flag == 0:
            tuple1 = get4Tuple()
            if tuple1[1] == 'TASSIGN':
                data.append(tuple[0]+' dd '+tuple1[2]+'\n')
            else :
                if tuple[3] == '#':
                    if tuple[2] == '1':
                        rodata.append(tuple[0]+' dd ?\n')
                    else :
                        rodata.append(tuple[0]+' dd '+str(int(tuple[2]))+' dup (?)\n')
                else :
                    rodata.append(tuple[0]+' dd '+str(int(tuple[2])*int(tuple[3]))+' dup (?)\n')
            index -= 1
        else :
            l_value.append(tuple[0])
            if tuple[3] == '#':
                if tuple[2] == '1':
                    code.append('\tLOCAL '+tuple[0]+proc_name+':DWORD\n')
                else :
                    code.append('\tLOCAL '+tuple[0]+proc_name+' ['+str(int(tuple[2]))+']:DWORD\n')
            else :
                code.append('\tLOCAL '+tuple[0]+proc_name+' ['+str(int(tuple[2])*int(tuple[3]))+']:DWORD\n')

    elif tuple[1] == 'PROCEDURE':
        code.append('\n'+tuple[0]+' proc ')
        local_flag = 1
        backup[0] = registers['eax']
        backup[1] = registers['ebx']
        backup[2] = registers['ecx']
        backup[3] = registers['edx']
        backup[4] = sav1
        backup[5] = sav2
        registers['eax'] = ''
        registers['ebx'] = ''
        registers['ecx'] = ''
        registers['edx'] = ''
        sav1 = ''
        sav2 = ''
        proc_name = tuple[0]
        l_value = []

    elif tuple[1] == 'ENDPROCEDURE':
        code.append('\tret\n'+tuple[0]+' endp\n')
        registers['eax'] = backup[0]
        registers['ebx'] = backup[1]
        registers['ecx'] = backup[2]
        registers['edx'] = backup[3]
        sav1 = backup[4]
        sav2 = backup[5]
        proc_name = ''
        
    elif tuple[1] == 'MAIN':
        code.append('\nmain proc\n')
        local_flag = 1

    elif tuple[1] == 'ENDMAIN':
        code.append('\tret\nmain endp\n')

    elif tuple[1] == 'BEGINFORMALPARAMETERLIST':
        l_parameter = {}

    elif tuple[1] == 'NOFORMALPARAMETERS':
        code.append('\n')
        
    elif tuple[1] == 'FORMALVPARAMETER':
        l_parameter[tuple[0]] = 'V'
        tuple1 = get4Tuple()
        if tuple1[1] == 'ENDFORMALPARAMETERLIST':
            code.append(tuple[0]+':DWORD\n')
        else :
            code.append(tuple[0]+':DWORD, ')
        index -= 1

    elif tuple[1] == 'FORMALRPARAMETER':
        l_parameter[tuple[0]] = 'R'
        tuple1 = get4Tuple()
        if tuple1[1] == 'ENDFORMALPARAMETERLIST':
            code.append(tuple[0]+':PTR DWORD\n')
        else :
            code.append(tuple[0]+':PTR DWORD, ')
        index -= 1

    elif tuple[1] == 'SACTUALVPARAMETER':
        if tuple[2][-2:-1] == 'n':
            data.append('str'+str(s_index)+'\tdb '+tuple[2][0:-3]+'",13,10,0\n')
        else :
            data.append('str'+str(s_index)+'\tdb '+tuple[2]+', 0\n')
        tuple1 = get4Tuple()
        if tuple1[1] == 'ENDPROCEDURECALL':
            tcode.append('ADDR str'+str(s_index)+'\n')
        else :
            tcode.append('ADDR str'+str(s_index)+', ')
        index -= 1
        s_index += 1
        
    elif tuple[1] == 'IACTUALVPARAMETER':
        tuple1 = get4Tuple()
        if tuple[2] in l_value and local_flag == 1:
            tuple[2] = tuple[2] + proc_name
        if tuple1[1] == 'ENDPROCEDURECALL':
            if haveReference2(tuple[2]) == '0':
                tcode.append(tuple[2]+'\n')
            else :
                code.append('\tmov esi, '+tuple[2]+'\n')
                tcode.append('dword ptr [esi]\n')
        else :
            if haveReference2(tuple[2]) == '0':
                tcode.append(tuple[2]+', ')
            else :
                code.append('\tmov esi, '+tuple[2]+'\n')
                tcode.append('dword ptr [esi], ')        
        index -= 1

    elif tuple[1] == 'IACTUALVSUBPARAMETER':
        if tuple[2] in l_value and local_flag == 1:
            tuple[2] = tuple[2] + proc_name
        reg1 = getRegister(tuple[3],' ')
        tuple1 = get4Tuple()
        if tuple1[1] == 'ENDPROCEDURECALL':
            tcode.append(tuple[2]+'['+reg1+'*4]\n')
        else :
            tcode.append(tuple[2]+'['+reg1+'*4], ')
        index -= 1
        freeRegister(reg1)

    elif tuple[1] == 'IACTUALRPARAMETER':
        if tuple[2] in l_value and local_flag == 1:
            tuple[2] = tuple[2] + proc_name
        tuple1 = get4Tuple()
        if tuple1[1] == 'ENDPROCEDURECALL':
            tcode.append('ADDR '+tuple[2]+'\n')
        else :
            tcode.append('ADDR '+tuple[2]+', ')
        index -= 1

    elif tuple[1] == 'IACTUALRSUBPARAMETER':
        if tuple[2] in l_value and local_flag == 1:
            tuple[2] = tuple[2] + proc_name
        reg1 = getRegister(tuple[3],' ')
        tuple1 = get4Tuple()
        if tuple1[1] == 'ENDPROCEDURECALL':
            tcode.append('ADDR '+tuple[2]+'['+reg1+'*4]\n')
        else :
            tcode.append('ADDR '+tuple[2]+'['+reg1+'*4], ')
        index -= 1
        freeRegister(reg1)
        
    elif tuple[1] == 'PROCEDURECALL':
        tuple1 = get4Tuple()
        if tuple[2] == 'PRINTF':
            if tuple1[1] == 'NOFORMALPARAMETERS':
                tcode.append('\tpushad\n\tinvoke crt_printf')
            else :
                tcode.append('\tpushad\n\tinvoke crt_printf, ')
        elif tuple[2] == 'SCANF':
            if tuple1[1] == 'NOFORMALPARAMETERS':
                tcode.append('\tpushad\n\tinvoke crt_scanf')
            else :
                tcode.append('\tpushad\n\tinvoke crt_scanf, ')
        else :
            if tuple1[1] == 'NOFORMALPARAMETERS':
                tcode.append('\tpushad\n\tinvoke '+tuple[0])
            else :
                tcode.append('\tpushad\n\tinvoke '+tuple[0]+', ')
        tuple1 = get4Tuple()
        tuple1 = get4Tuple()
        if tuple1[1] == 'ENDPROCEDURECALL':
            tcode.append('\n')
        index -= 3
        call_flag = 1

    elif tuple[1] == 'ENDPROCEDURECALL':
        code = code + tcode
        tcode = []
        code.append('\tpopad\n')
        call_flag = 0

    elif tuple[1] == 'ILESSEQUAL':
        if tuple[2] in l_value and local_flag == 1:
            tuple[2] = tuple[2] + proc_name
        if tuple[3] in l_value and local_flag == 1:
            tuple[3] = tuple[3] + proc_name
        reg1 = getRegister(tuple[2],' ')
        reg2 = getRegister(tuple[3],reg1)
        code.append('\tcmp '+reg1+', '+reg2+'\n')
        tuple1 = get4Tuple()
        if tuple1[1] == 'CJUMP':
            code.append('\tjg '+tuple1[0]+'\n')
        freeRegister(reg1)
        freeRegister(reg2)
            
    elif tuple[1] == 'ILESSTHAN':
        if tuple[2] in l_value and local_flag == 1:
            tuple[2] = tuple[2] + proc_name
        if tuple[3] in l_value and local_flag == 1:
            tuple[3] = tuple[3] + proc_name
        reg1 = getRegister(tuple[2],' ')
        reg2 = getRegister(tuple[3],reg1)
        code.append('\tcmp '+reg1+', '+reg2+'\n')
        tuple1 = get4Tuple()
        if tuple1[1] == 'CJUMP':
            code.append('\tjnl '+tuple1[0]+'\n')
        freeRegister(reg1)
        freeRegister(reg2)

    elif tuple[1] == 'IGREATERTHAN':
        if tuple[2] in l_value and local_flag == 1:
            tuple[2] = tuple[2] + proc_name
        if tuple[3] in l_value and local_flag == 1:
            tuple[3] = tuple[3] + proc_name
        reg1 = getRegister(tuple[2],' ')
        reg2 = getRegister(tuple[3],reg1)
        code.append('\tcmp '+reg1+', '+reg2+'\n')
        tuple1 = get4Tuple()
        if tuple1[1] == 'CJUMP':
            code.append('\tjng '+tuple1[0]+'\n')
        freeRegister(reg1)
        freeRegister(reg2)

    elif tuple[1] == 'IGREATEREQUAL':
        if tuple[2] in l_value and local_flag == 1:
            tuple[2] = tuple[2] + proc_name
        if tuple[3] in l_value and local_flag == 1:
            tuple[3] = tuple[3] + proc_name
        reg1 = getRegister(tuple[2],' ')
        reg2 = getRegister(tuple[3],reg1)
        code.append('\tcmp '+reg1+', '+reg2+'\n')
        tuple1 = get4Tuple()
        if tuple1[1] == 'CJUMP':
            code.append('\tjl '+tuple1[0]+'\n')
        freeRegister(reg1)
        freeRegister(reg2)

    elif tuple[1] == 'IEQUAL':
        if tuple[2] in l_value and local_flag == 1:
            tuple[2] = tuple[2] + proc_name
        if tuple[3] in l_value and local_flag == 1:
            tuple[3] = tuple[3] + proc_name
        reg1 = getRegister(tuple[2],' ')
        reg2 = getRegister(tuple[3],reg1)
        code.append('\tcmp '+reg1+', '+reg2+'\n')
        tuple1 = get4Tuple()
        if tuple1[1] == 'CJUMP':
            code.append('\tjne '+tuple1[0]+'\n')
        freeRegister(reg1)
        freeRegister(reg2)

    elif tuple[1] == 'INOTEQUAL':
        if tuple[2] in l_value and local_flag == 1:
            tuple[2] = tuple[2] + proc_name
        if tuple[3] in l_value and local_flag == 1:
            tuple[3] = tuple[3] + proc_name
        reg1 = getRegister(tuple[2],' ')
        reg2 = getRegister(tuple[3],reg1)
        code.append('\tcmp '+reg1+', '+reg2+'\n')
        tuple1 = get4Tuple()
        if tuple1[1] == 'CJUMP':
            code.append('\tje '+tuple1[0]+'\n')
        freeRegister(reg1)
        freeRegister(reg2)        
        
    elif tuple[1] == 'JUMP':
        code.append('\tjmp '+tuple[0]+'\n')

    elif tuple[1] == 'LABEL':
        code.append(tuple[0]+':\n')
        registers['eax'] = ''
        registers['ebx'] = ''
        registers['ecx'] = ''
        registers['edx'] = ''
        sav1 = ''
        sav2 = ''
            
    elif tuple[1] == 'STORE':
        if tuple[2] in l_value and local_flag == 1:
            tuple[2] = tuple[2] + proc_name
        if tuple[0] in l_value and local_flag == 1:
            tuple[0] = tuple[0] + proc_name
        if haveReference(tuple[2], tuple[0]) == '00':
            reg1 = getRegister(tuple[2],' ')
            code.append('\tmov '+tuple[0]+', '+reg1+'\n')
            reg2 = getRegister(tuple[0],reg1)
            code.append('\tmov '+reg2+', '+reg1+'\n')
            freeRegister(reg1)
        if haveReference(tuple[2], tuple[0]) == '10':
            reg1 = getPointRegister(tuple[2])
            code.append('\tmov '+tuple[0]+', '+reg1+'\n')
            reg2 = getRegister(tuple[0],reg1)
            code.append('\tmov '+reg2+', '+reg1+'\n')
        if haveReference(tuple[2], tuple[0]) == '01':
            reg1 = getRegister(tuple[2],' ')
            reg2 = getPointRegister(tuple[0])
            code.append('\tmov '+reg2+', '+reg1+'\n')
            code.append('\tmov dword ptr [esi], '+reg2+'\n')
            freeRegister(reg1)            
        if haveReference(tuple[2], tuple[0]) == '11':
            reg1 = getPointRegister(tuple[2])
            reg2 = getPointRegister(tuple[0])
            code.append('\tmov '+reg2+', '+reg1+'\n')
            code.append('\tmov dword ptr [esi], '+reg2+'\n')

    elif tuple[1] == 'SUBSTORE': 
        if tuple[2] in l_value and local_flag == 1:
            tuple[2] = tuple[2] + proc_name
        if tuple[3] in l_value and local_flag == 1:
            tuple[3] = tuple[3] + proc_name
        reg2 = getRegister(tuple[2],' ')
        reg3 = getRegister(tuple[3],reg2)
        code.append('\tmov '+tuple[0]+'['+reg3+'*4], '+reg2+'\n')
        freeRegister(reg2)
        freeRegister(reg3)

    elif tuple[1] == 'SUBLOAD':
        if tuple[2] in l_value and local_flag == 1:
            tuple[2] = tuple[2] + proc_name
        if tuple[0] in l_value and local_flag == 1:
            tuple[0] = tuple[0] + proc_name
        reg1 = getRegister(tuple[3],' ')
        freeRegister(reg1)
        reg2 = getRegister(tuple[0],' ')
        code.append('\tmov '+reg2+', '+tuple[2]+'['+reg1+'*4]\n')

    elif tuple[1] == 'IADD':
        if tuple[2] in l_value and local_flag == 1:
            tuple[2] = tuple[2] + proc_name
        if tuple[3] in l_value and local_flag == 1:
            tuple[3] = tuple[3] + proc_name
        if haveReference(tuple[2], tuple[3]) == '00':
            reg1 = getRegister(tuple[2],' ')
            reg2 = getRegister(tuple[3],reg1)
            code.append('\tadd '+reg1+', '+reg2+'\n')
            freeRegister(reg2)
            registers[reg1] = tuple[0]
        if haveReference(tuple[2], tuple[3]) == '10':
            reg1 = getPointRegister(tuple[2])
            reg2 = getRegister(tuple[3],reg1)
            code.append('\tadd '+reg1+', '+reg2+'\n')
            freeRegister(reg2)
            registers[reg1] = tuple[0]
        if haveReference(tuple[2], tuple[3]) == '01':
            reg1 = getRegister(tuple[2])
            reg2 = getPointRegister(tuple[3])
            code.append('\tadd '+reg1+', '+reg2+'\n')
            registers[reg1] = tuple[0]            
        if haveReference(tuple[2], tuple[3]) == '11':
            reg1 = getPointRegister(tuple[2])
            reg2 = getPointRegister(tuple[3])
            code.append('\tadd '+reg1+', '+reg2+'\n')
            registers[reg1] = tuple[0]

    elif tuple[1] == 'ISUB':
        if tuple[2] in l_value and local_flag == 1:
            tuple[2] = tuple[2] + proc_name
        if tuple[3] in l_value and local_flag == 1:
            tuple[3] = tuple[3] + proc_name
        if haveReference(tuple[2], tuple[3]) == '00':
            reg1 = getRegister(tuple[2],' ')
            reg2 = getRegister(tuple[3],reg1)
            code.append('\tsub '+reg1+', '+reg2+'\n')
            freeRegister(reg2)
            registers[reg1] = tuple[0]
        if haveReference(tuple[2], tuple[3]) == '10':
            reg1 = getPointRegister(tuple[2])
            reg2 = getRegister(tuple[3],reg1)
            code.append('\tsub '+reg1+', '+reg2+'\n')
            freeRegister(reg2)
            registers[reg1] = tuple[0]
        if haveReference(tuple[2], tuple[3]) == '01':
            reg1 = getRegister(tuple[2])
            reg2 = getPointRegister(tuple[3])
            code.append('\tsub '+reg1+', '+reg2+'\n')
            registers[reg1] = tuple[0]            
        if haveReference(tuple[2], tuple[3]) == '11':
            reg1 = getPointRegister(tuple[2])
            reg2 = getPointRegister(tuple[3])
            code.append('\tsub '+reg1+', '+reg2+'\n')
            registers[reg1] = tuple[0]            

    elif tuple[1] == 'IMULT':
        if tuple[2] in l_value and local_flag == 1:
            tuple[2] = tuple[2] + proc_name
        if tuple[3] in l_value and local_flag == 1:
            tuple[3] = tuple[3] + proc_name
        if haveReference(tuple[2], tuple[3]) == '00':
            reg1 = getRegister(tuple[2],' ')
            reg2 = getRegister(tuple[3],reg1)
            code.append('\timul '+reg1+', '+reg2+'\n')
            freeRegister(reg2)
            registers[reg1] = tuple[0]
        if haveReference(tuple[2], tuple[3]) == '10':
            reg1 = getPointRegister(tuple[2])
            reg2 = getRegister(tuple[3],reg1)
            code.append('\timul '+reg1+', '+reg2+'\n')
            freeRegister(reg2)
            registers[reg1] = tuple[0]
        if haveReference(tuple[2], tuple[3]) == '01':
            reg1 = getRegister(tuple[2])
            reg2 = getPointRegister(tuple[3])
            code.append('\timul '+reg1+', '+reg2+'\n')
            registers[reg1] = tuple[0]            
        if haveReference(tuple[2], tuple[3]) == '11':
            reg1 = getPointRegister(tuple[2])
            reg2 = getPointRegister(tuple[3])
            code.append('\timul '+reg1+', '+reg2+'\n')
            registers[reg1] = tuple[0]       

def pragmatics():
    print Global.tuples
    length = len(Global.tuples)-1
    while index < length:
        _pragmatics()
    printASM()

def printASM():
    for i in env:
        Global.outputFile.write(i)
    for i in rodata:
        Global.outputFile.write(i)
    for i in data:
        Global.outputFile.write(i)
    for i in code:
        Global.outputFile.write(i)
